﻿/*
COPYRIGHT (C) 2009 EPISERVER AB

THIS FILE IS PART OF REMOTE PAGE PROVIDER FOR EPISERVER CMS.
REMOTE PAGE PROVIDER FOR EPISERVER CMS IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

REMOTE PAGE PROVIDER FOR EPISERVER CMS IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER GENERAL PUBLIC LICENSE FOR MORE DETAILS.
YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH REMOTE PAGE PROVIDER FOR EPISERVER CMS]. IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using EPiServer.Security;
using System.Web.Security;
using System.Threading;
using System.ServiceModel;
using EPiServer.Core;
using System.IO;
using System.Diagnostics;

namespace EPiServer.Labs.RemoteProvider
{

    /// <summary>
    /// RemoteProviderContextManager Class helps the operation calls with the correct context
    /// </summary>
    static class RemoteProviderContextManager 
    {
        public delegate void CallOperation();
        static object _syncObject = new object();



        /// <summary>
        /// Calls the operation with switch context.
        /// </summary>
        /// <param name="principal">The principal.</param>
        /// <param name="operation">The operation.</param>
        public static void CallOperationWithSwitchContext(IPrincipal principal, CallOperation operation)
        {
                IPrincipal originalPricipal = PrincipalInfo.CurrentPrincipal;
                try
                {
                    PrincipalInfo.CurrentPrincipal = principal;
                    operation();
                }
                finally
                {
                    PrincipalInfo.CurrentPrincipal = originalPricipal;
                }
        }
    }


    /// <summary>
    /// RemoteProviderData
    /// </summary>
    public class RemoteProviderData
    {
        public PrincipalInfo PrincipalInfo
        {
            get;
            set;
        }

        public InitializeData InitializeData
        {
            get;
            set;
        }

        public RemoteProviderData(InitializeData initializeData)
        {
            InitializeData = initializeData;
            if (!string.IsNullOrEmpty(InitializeData.Credential.UserName))
            {
                if (Membership.ValidateUser(initializeData.Credential.UserName, initializeData.Credential.Password))
                {
                    PrincipalInfo = new PrincipalInfo(PrincipalInfo.CreatePrincipal(InitializeData.Credential.UserName));
                }
                else
                {
                    throw new EPiServerException(string.Format("The user {0} is not Authenticated by system. Please insert a valid user in Web config", InitializeData.Credential.UserName));
                }
            }
        }

    }

    /// <summary>
    /// 
    /// </summary>
    public class RemoteProviderDataManager
    {
        private static Dictionary<string, RemoteProviderData> _RemoteProviderData = new Dictionary<string, RemoteProviderData>(10);
        private static Dictionary<string, RemoteProviderData> _liveRemoteProviderData = new Dictionary<string, RemoteProviderData>(10);
        private static object _lockObject = new Object();

        /// <summary>
        /// Adds the specified session object.
        /// </summary>
        /// <param name="sessionObject">The session object.</param>
        /// <param name="RemoteProviderData">The remote page provider data.</param>
        public void Add(OperationContext sessionObject, RemoteProviderData RemoteProviderData)
        {
            Add(GetKey(sessionObject), RemoteProviderData);
        }

        /// <summary>
        /// Adds the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="RemoteProviderData">The remote page provider data.</param>
        public void Add(string  key, RemoteProviderData RemoteProviderData)
        {
            Dictionary<string, RemoteProviderData> temp;
            lock (_lockObject)
            {
                RemoteProviderData tmpRemoteProvider;
                if(_RemoteProviderData.TryGetValue(key, out tmpRemoteProvider))
                {
                    if (tmpRemoteProvider == RemoteProviderData)
                    {
                        return;
                    }
                    Remove(key);
                }
                _RemoteProviderData.Add(key, RemoteProviderData);
                temp = new Dictionary<string, RemoteProviderData>(_RemoteProviderData);
            }
            _liveRemoteProviderData = temp;
        }

        /// <summary>
        /// Removes the specified session object.
        /// </summary>
        /// <param name="sessionObject">The session object.</param>
        public void Remove(OperationContext sessionObject)
        {
            Remove(GetKey(sessionObject));
        }

        /// <summary>
        /// Removes the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        public void Remove(string key)
        {
            Dictionary<string, RemoteProviderData> temp;
            lock (_lockObject)
            {
                _RemoteProviderData.Remove(key);
                temp = new Dictionary<string, RemoteProviderData>(_RemoteProviderData);
            }
            _liveRemoteProviderData = temp;
        }

        /// <summary>
        /// Tries the get value.
        /// </summary>
        /// <param name="sessionObject">The session object.</param>
        /// <param name="RemoteProviderData">The remote page provider data.</param>
        /// <returns></returns>
        public bool TryGetValue(OperationContext sessionObject, out RemoteProviderData RemoteProviderData)
        {
            return TryGetValue(GetKey(sessionObject), out RemoteProviderData);
        }

        /// <summary>
        /// Tries the get value.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="RemoteProviderData">The remote page provider data.</param>
        /// <returns></returns>
        public bool TryGetValue(string key, out RemoteProviderData RemoteProviderData)
        {
            return _liveRemoteProviderData.TryGetValue(key, out RemoteProviderData);
        }

        /// <summary>
        /// Gets the key.
        /// </summary>
        /// <param name="sessionObject">The session object.</param>
        /// <returns></returns>
        private string GetKey(OperationContext sessionObject)
        {
            if (sessionObject != null)
            {
                return sessionObject.SessionId;
            }

            if (Global.IsUnitTest)
            {
                return "unitTestSessionID";
            }
            return string.Empty;
        }
    }
}
